package gestordeentidades.idgenerators;

import gestordeentidades.persistance.DataBaseObject;
import gestordeentidades.persistance.database.Converter;
import gestordeentidades.persistance.interfaces.IDataBaseAdapter;
import gestordeentidades.persistance.interfaces.IDataBaseRow;
import gestordeentidades.persistance.interfaces.IDataBaseStatement;
import gestordeentidades.persistance.interfaces.ILinha;
import java.util.HashMap;
import java.util.Map;

/**
 * Trabalho DAS - 2014/2015
 * Gerador de ids para cada tabela
 * @author a21210380, a21190325, a21210392
 */
public class IDgenerator implements IIDgenerator {
    public static final String SQL_CREATE = "CREATE TABLE IF NOT EXISTS id_generator ("
                                           +"nome " + Converter.convertToSqlText(String.class) + " NOT NULL,"
                                           +"atual " + Converter.convertToSqlText(int.class) + " NOT NULL);";
    public static final String SQL_DROP = "DROP TABLE id_generator;";
    public static final String SQL_INSERT = "INSERT INTO id_generator VALUES (?,?);";
    public static final String SQL_UPDATE = "UPDATE id_generator SET atual=? WHERE nome=?;";
    public static final String SQL_FIND_ALL = "SELECT * FROM id_generator;";
    
    private final Object lock = new Object();
    private final IDataBaseAdapter dataBase;
    private final Map<String, Integer> ids = new HashMap<>();
    private final IDataBaseRow dataBaseRow = (ILinha linha) -> {
        synchronized(lock) {
            if(ids.containsKey(linha.getString("nome"))) {
                ids.remove(linha.getString("nome"));
            }
            ids.put(linha.getString("nome"), linha.getInt("atual"));
        }
    };
    
    public IDgenerator(IDataBaseAdapter dataBase) {
        this.dataBase = dataBase;
    }
    
    public IDgenerator initDataBase() {
        dataBase.executarSql(SQL_CREATE);
        return this;
    }
    
    public IDgenerator dropTable() {
        dataBase.executarSql(SQL_DROP);
        return this;
    }
    
    @Override
    public IDgenerator load() {
        synchronized(lock) {
            ids.clear();
            IDataBaseStatement dataBaseStatement = dataBase.getDataBaseStatement(SQL_FIND_ALL);
            dataBase.ler(dataBaseStatement, dataBaseRow);
        }
        return this;
    }
    
    public <T extends DataBaseObject> IDgenerator iniciarEntidade(Class<T> entidade) {
        synchronized(lock) {
            if(ids.containsKey(entidade.getName())) {
                return this;
            }
            IDataBaseStatement dataBaseStatement = dataBase.getDataBaseStatement(SQL_INSERT);
            dataBaseStatement.adicionarParametroSql(1, entidade.getName(), Converter.convertToSqlText(String.class));
            dataBaseStatement.adicionarParametroSql(2, 0, Converter.convertToSqlText(int.class));

            if(dataBase.inserir(dataBaseStatement) == 1) {
                ids.put(entidade.getName(), 0);
            }
            return this;
        }
    }
    
    @Override
    public IDgenerator guardar() {
        synchronized(lock) {
            ids.forEach((v, k)-> {
                IDataBaseStatement dataBaseStatement = dataBase.getDataBaseStatement(SQL_UPDATE);
                dataBaseStatement.adicionarParametroSql(1, k, Converter.convertToSqlText(int.class));
                dataBaseStatement.adicionarParametroSql(2, v, Converter.convertToSqlText(String.class));
                dataBase.atualizar(dataBaseStatement);
            });
            return this;
        }
    }
    
    @Override
    public <T extends DataBaseObject> int getNextId(Class<T> entidade) {
        synchronized(lock) {
            if(ids.containsKey(entidade.getName())) {
                Integer get = ids.remove(entidade.getName());
                int novo = get + 1;
                ids.put(entidade.getName(), novo);
                return novo;
            } 
        }
        throw new IllegalStateException(entidade.getName() + " não está inicializada!");
    }
}
